﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using Team6_Algorithms.HighEnd;
using Team6_Algorithms.AidingClasses;
using System.Drawing.Imaging;

namespace Team6_Algorithms.Binary
{
    /// <summary>
    /// Class for making binary images ( and returning them in distinct ways ), and several other functions like
    /// making a new bitmap from pixelpoint arrays
    /// Made by Dylan Snel && Pascal Schotman && Alexander Streng
    /// </summary>
    public class Binaryze
    {

        private static Bitmap b;
        private static int[,] Points;
        private static int[] SinglePoints;

        /// <summary>
        /// Convert a bitmap to a 2d- binary array of pixelpoints.
        /// the returned pixelpoints either have an id of 1 ( foreground ) or 0 ( background )
        /// </summary>
        /// <param name="B">input bitmap</param>
        /// <returns>A 2d- array of pixelpoints</returns>
        public static object[,] MakeBinairy(Bitmap B)
        {
            PixelPoint[,] PP = new PixelPoint[B.Width, B.Height];

            Bitmap bSrc = (Bitmap)B.Clone();
            BitmapData BmData = B.LockBits(new Rectangle(0, 0, B.Width, B.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            BitmapData BmSrc = bSrc.LockBits(new Rectangle(0, 0, bSrc.Width, bSrc.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            int stride = BmData.Stride;
            int nWidth = B.Width;
            int nHeight = B.Height;
            int pointerShift;
            System.IntPtr Scan0 = BmData.Scan0;
            System.IntPtr SrcScan0 = BmSrc.Scan0;

            //Find the directions and strenghts of the edges
            unsafe
            {

                byte* p = (byte*)(void*)Scan0;
                byte* pSrc = (byte*)(void*)SrcScan0;

                int x = 0, y = 0;
                for (y = 0; y < nHeight; y++)
                {
                    for (x = 0; x < nWidth; x++)
                    {
                        pointerShift = (y * stride) + (x * 3);
                        if (p[pointerShift + 2] + p[pointerShift + 1] + p[pointerShift + 0] > 0)
                        {
                            PP[x, y] = new PixelPoint(x, y, 1, p[pointerShift + 2], p[pointerShift + 1], p[pointerShift + 0], null);
                        }
                        else
                        {
                            PP[x, y] = new PixelPoint(x, y, 0, p[pointerShift + 2], p[pointerShift + 1], p[pointerShift + 0], null);
                        }

                    }
                }
            }
            B.UnlockBits(BmData);
            bSrc.UnlockBits(BmSrc);

            return PP;
        }

        /// <summary>
        /// Convert a bitmap to a 2d- binary array of pixelpoints.
        /// the returned pixelpoints either have an id of 0 ( foreground ) or 1 ( background )
        /// </summary>
        /// <param name="B">input bitmap</param>
        /// <returns>A 2d- array of inverted pixelpoints</returns>
        public static object[,] InvertBinary(Bitmap B)
        {
            PixelPoint[,] PP = new PixelPoint[B.Width, B.Height];

            Bitmap bSrc = (Bitmap)B.Clone();
            BitmapData BmData = B.LockBits(new Rectangle(0, 0, B.Width, B.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            BitmapData BmSrc = bSrc.LockBits(new Rectangle(0, 0, bSrc.Width, bSrc.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            int stride = BmData.Stride;
            int nWidth = B.Width;
            int nHeight = B.Height;
            int pointerShift;
            System.IntPtr Scan0 = BmData.Scan0;
            System.IntPtr SrcScan0 = BmSrc.Scan0;

            //Find the directions and strenghts of the edges
            unsafe
            {

                byte* p = (byte*)(void*)Scan0;
                byte* pSrc = (byte*)(void*)SrcScan0;

                int x = 0, y = 0;
                for (y = 0; y < nHeight; y++)
                {
                    for (x = 0; x < nWidth; x++)
                    {
                        pointerShift = (y * stride) + (x * 3);
                        if (p[pointerShift + 2] + p[pointerShift + 1] + p[pointerShift + 0] < 400)
                        {
                            PP[x, y] = new PixelPoint(x, y, 1, p[pointerShift + 2], p[pointerShift + 1], p[pointerShift + 0], null);
                        }
                        else
                        {
                            PP[x, y] = new PixelPoint(x, y, 0, p[pointerShift + 2], p[pointerShift + 1], p[pointerShift + 0], null);
                        }

                    }
                }
            }
            B.UnlockBits(BmData);
            bSrc.UnlockBits(BmSrc);

            return PP;
        }

        /// <summary>
        /// Convert a bitmap to a 2d- binary array of ints.
        /// the returned array contains ints of 1 ( foreground ) or 0 ( background )
        /// </summary>k
        /// <param name="B">input bitmap</param>
        /// <returns>A 2d- array of ints</returns>
        public static int[,] MakeBinaryIntImageInverted(Bitmap bitmap)
        {
            b = bitmap;
            Points = new int[b.Width, b.Height];

            BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height),
            ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

            int stride = bmData.Stride;

            System.IntPtr Scan0 = bmData.Scan0;

            unsafe
            {
                byte* p = (byte*)(void*)Scan0;

                int nOffset = stride - b.Width * 3;

                byte red, green, blue;

                for (int y = 0; y < b.Height; ++y)
                {
                    for (int x = 0; x < b.Width; ++x)
                    {
                        blue = p[0];
                        green = p[1];
                        red = p[2];

                        if ((red + green + blue / 3) > 200)
                        {
                            Points[x, y] = 0;
                        }
                        else
                        {
                            Points[x, y] = 1;
                        }

                        p += 3;
                    }
                    p += nOffset;
                }
            }
            b.UnlockBits(bmData);

            return Points;
        }

        /// <summary>
        /// Convert a bitmap to a array of ints.
        /// the returned array contains ints of 1 ( foreground ) or 0 ( background )
        /// </summary>
        /// <param name="B">input bitmap</param>
        /// <returns>A array of ints</returns>
        public static int[] MakeBinarySingleIntImageInverted(Bitmap bitmap)
        {
            b = bitmap;

            SinglePoints = new int[b.Width * b.Height];

            BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height),
            ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

            int stride = bmData.Stride;

            System.IntPtr Scan0 = bmData.Scan0;

            unsafe
            {
                byte* p = (byte*)(void*)Scan0;

                int nOffset = stride - b.Width * 3;

                byte red, green, blue;

                for (int y = 0; y < b.Height; ++y)
                {
                    for (int x = 0; x < b.Width; ++x)
                    {
                        blue = p[0];
                        green = p[1];
                        red = p[2];

                        if ((red + green + blue / 3) > 200)
                        {
                            SinglePoints[y * b.Width + x] = 0;
                        }
                        else
                        {
                            SinglePoints[y * b.Width + x] = 1;
                        }

                        p += 3;
                    }
                    p += nOffset;
                }
            }
            b.UnlockBits(bmData);

            return SinglePoints;
        }

        /// <summary>
        /// Make a bitmap from the given 2d - array of pixel points
        /// </summary>
        /// <param name="B">The bitmap on which the image will be drawn</param>
        /// <param name="PP">the array of pixelpoints from which data will be read.</param>
        /// <returns>the new painted bitmap</returns>
        public static Bitmap PaintBinairy(Bitmap B, PixelPoint[,] PP)
        {


            Bitmap bSrc = (Bitmap)B.Clone();
            BitmapData BmData = B.LockBits(new Rectangle(0, 0, B.Width, B.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            BitmapData BmSrc = bSrc.LockBits(new Rectangle(0, 0, bSrc.Width, bSrc.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            int stride = BmData.Stride;
            int nWidth = B.Width;
            int nHeight = B.Height;
            int pointerShift;
            System.IntPtr Scan0 = BmData.Scan0;
            System.IntPtr SrcScan0 = BmSrc.Scan0;

            //Find the directions and strenghts of the edges
            unsafe
            {

                byte* p = (byte*)(void*)Scan0;
                byte* pSrc = (byte*)(void*)SrcScan0;

                int x = 0, y = 0;
                for (y = 0; y < nHeight; y++)
                {
                    for (x = 0; x < nWidth; x++)
                    {
                        pointerShift = (y * stride) + (x * 3);
                        if (PP[x, y].id == 1)
                        {
                            p[pointerShift + 2] = 255;
                            p[pointerShift + 1] = 255;
                            p[pointerShift + 0] = 255;

                        }
                        else
                        {
                            p[pointerShift + 2] = 0;
                            p[pointerShift + 1] = 0;
                            p[pointerShift + 0] = 0;
                        }

                    }
                }
            }
            B.UnlockBits(BmData);
            bSrc.UnlockBits(BmSrc);

            return B;
        }

        /// <summary>
        /// Make a bitmap from the given 2d - array of inverted pixel points
        /// </summary>
        /// <param name="B">The bitmap on which the image will be drawn</param>
        /// <param name="PP">the array of pixelpoints from which data will be read.</param>
        /// <returns>the new inverted painted bitmap</returns>
        public static Bitmap PaintInvertedBinairy(Bitmap B, PixelPoint[,] PP)
        {
            Bitmap bSrc = (Bitmap)B.Clone();
            BitmapData BmData = B.LockBits(new Rectangle(0, 0, B.Width, B.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            BitmapData BmSrc = bSrc.LockBits(new Rectangle(0, 0, bSrc.Width, bSrc.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            int stride = BmData.Stride;
            int nWidth = B.Width;
            int nHeight = B.Height;
            int pointerShift;
            System.IntPtr Scan0 = BmData.Scan0;
            System.IntPtr SrcScan0 = BmSrc.Scan0;

            //Find the directions and strenghts of the edges
            unsafe
            {

                byte* p = (byte*)(void*)Scan0;
                byte* pSrc = (byte*)(void*)SrcScan0;

                int x = 0, y = 0;
                for (y = 0; y < nHeight; y++)
                {
                    for (x = 0; x < nWidth; x++)
                    {
                        pointerShift = (y * stride) + (x * 3);
                        if (PP[x, y].id == 1)
                        {
                            p[pointerShift + 2] = 0;
                            p[pointerShift + 1] = 0;
                            p[pointerShift + 0] = 0;

                        }
                        else
                        {
                            p[pointerShift + 2] = 255;
                            p[pointerShift + 1] = 255;
                            p[pointerShift + 0] = 255;
                        }

                    }
                }
            }
            B.UnlockBits(BmData);
            bSrc.UnlockBits(BmSrc);

            return B;
        }

        /// <summary>
        /// Make a bitmap from the given 2d - array of Ints
        /// </summary>
        /// <param name="B">The bitmap on which the image will be drawn</param>
        /// <param name="_Points">the array of Ints from which data will be read.</param>
        /// <returns>the new painted bitmap</returns>
        public static Bitmap PaintInvertedIntBinairy(Bitmap B, int[,] _Points)
        {
            Points = _Points;

            Bitmap bSrc = (Bitmap)B.Clone();
            BitmapData BmData = B.LockBits(new Rectangle(0, 0, B.Width, B.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            BitmapData BmSrc = bSrc.LockBits(new Rectangle(0, 0, bSrc.Width, bSrc.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            int stride = BmData.Stride;
            int nWidth = B.Width;
            int nHeight = B.Height;
            int pointerShift;
            System.IntPtr Scan0 = BmData.Scan0;
            System.IntPtr SrcScan0 = BmSrc.Scan0;

            //Find the directions and strenghts of the edges
            unsafe
            {

                byte* p = (byte*)(void*)Scan0;
                byte* pSrc = (byte*)(void*)SrcScan0;

                for (int y = 0; y < nHeight; y++)
                {
                    for (int x = 0; x < nWidth; x++)
                    {
                        pointerShift = (y * stride) + (x * 3);
                        if (Points[x, y] == 1)
                        {
                            p[pointerShift + 2] = 0;
                            p[pointerShift + 1] = 0;
                            p[pointerShift + 0] = 0;

                        }
                        else
                        {
                            p[pointerShift + 2] = 255;
                            p[pointerShift + 1] = 255;
                            p[pointerShift + 0] = 255;
                        }

                    }
                }
            }
            B.UnlockBits(BmData);
            bSrc.UnlockBits(BmSrc);

            return B;
        }

    }
}
